package auth

import (
	"context"
	"time"

	"code.byted.org/bytertc/whiteboard_server/biz/api"

	"code.byted.org/bytertc/whiteboard_server/biz/pkg/biz_error"
	"code.byted.org/bytertc/whiteboard_server/kitex_gen/toutiao/videoarch/rtc_api_v2"
	"code.byted.org/bytertc/whiteboard_server/kitex_gen/toutiao/videoarch/rtc_api_v2/rtcapi"
	"code.byted.org/gopkg/logs/v2/log"
	"code.byted.org/videoarch/oner_auth_pkg/auth"
	"code.byted.org/videoarch/oner_common/util"
	"github.com/pkg/errors"
)

type TokenHelper interface {
	Check(ctx context.Context, token string, isByte bool) (*api.AuthTokenKeyParams, error)
	Generate(ctx context.Context, onerApp, userID, roomId string) (byteApp, token string, err error)
}

var _ TokenHelper = (*helper)(nil)

type helper struct {
	rtcAPI rtcapi.Client
}

func NewTokenHelper(rtcAPI rtcapi.Client) TokenHelper {
	return &helper{
		rtcAPI: rtcAPI,
	}
}

func (c *helper) Check(ctx context.Context, token string, isByte bool) (*api.AuthTokenKeyParams, error) {
	if isByte {
		return c.checkByteToken(ctx, token)
	}
	return c.checkOnerToken(ctx, token)
}

func (c *helper) checkOnerToken(ctx context.Context, token string) (*api.AuthTokenKeyParams, error) {
	resp, err := auth.CheckToken(ctx, &auth.CheckTokenReq{Token: token})
	params := &api.AuthTokenKeyParams{
		AppID:    resp.AppID,
		RoomID:   resp.RoomID,
		Operator: resp.UserID,
	}
	return params, err
}

func (c *helper) checkByteToken(ctx context.Context, token string) (*api.AuthTokenKeyParams, error) {
	param := rtc_api_v2.NewTCheckToken2Param()
	param.Token = token
	param.IgnoreRoomID = true
	resp, err := c.rtcAPI.CheckToken2(ctx, param)
	if err != nil {
		return nil, biz_error.UnknownError.Wrap(err)
	}
	if resp.BaseResp.StatusCode != 0 {
		return nil, biz_error.CheckTokenError.Wrap(
			errors.Errorf("rtc api return %d : %s", resp.BaseResp.StatusCode, resp.BaseResp.StatusMessage))
	}
	params := &api.AuthTokenKeyParams{
		AppID:    resp.Service,
		RoomID:   resp.RoomName,
		Operator: resp.UserName,
	}
	return params, nil
}

func (c *helper) Generate(ctx context.Context, onerApp, userID, roomId string) (string, string, error) {
	byteApp, ok := util.GetApp(onerApp, "byte")
	if !ok {
		return "", "", biz_error.GenTokenError.Wrap(errors.Errorf("on such oner app %s", onerApp))
	}
	expireTime := time.Now().Add(time.Hour * 24)
	byteToken := New(byteApp.AppID, byteApp.AppKey, roomId, userID)
	byteToken.AddPrivilege(PrivPublishStream, expireTime)
	byteToken.AddPrivilege(PrivSubscribeStream, expireTime)
	byteToken.ExpireTime(expireTime)
	token, err := byteToken.Serialize()
	log.V1.CtxInfo(ctx, "gen token for byte app %s, user %s", byteApp.AppID, userID)
	return byteApp.AppID, token, biz_error.GenTokenError.Wrap(errors.WithStack(err))
}
